본문으로 건너뛰기

23.06.15

오늘 한 일

  • 알고리즘 문제 풀이
  • vanilla-react 를 JS -> TS로 마이그레이션 진행

하루 요약

3~5시 / 6~10시 까지 카페에서 세림이랑 공부했다.

알고리즘 2문제 풀고, vanilla-react를 TS로 마이그레이션 진행했다.

이번에 테오 스프린트 15기가 올라왔다! 작년에 13기 했었는데, 이번에 또 신청했다. 친구들도 같이 신청해서 스프린트 같이 하면

주저리 주저리

일정이 꽉꽉 찼다. 만약에 구름톤까지 붙게되면 해커톤을 연속으로 세번할 수도 있을 것 같다 ㅋㅋ

6/21 -> 6/26 : 테오 스프린트 15기 6/28 -> 6/30 : 학교 해커톤 7/7 -> 7/10 : 구름톤?

스프린트 기간동안 GDG 사람을 찾습니다 컨퍼런스 가서 사이드 프로젝트 진행할 수도 있다.. 너무 많나?😂


vanilla-react를 JS -> TS로 마이그레이션 진행

레포

저번 스터디에서 했던 것을 개인 레포로 옮겨서 진행했다.

자바스크립트로 짠 코드를 타입스크립트로 마이그레이션했다.

우아한형제들 이정민님의 vanilla_react 레포를 보니 타입스크립트로 구현되어있다. 이 레포를 보고 참고해서 진행했다.

스터디 때 타입스크립트를 써서 구현할까 생각했었는데, 좀 오래걸릴 것 같아서 자바스크립트로 진행했었다. 그래서 이번 기회에 바꿔보았다.

세팅

타입스크립트를 적용하기 위해서 필요한 라이브러리들을 설치했다.

$ yarn add -D typescript @babel/preset-typescript

그리고 .babelrc 파일을 수정했다.

@babel/preset-typescript를 추가하는 이유는 babel과 typescript를 함께 사용하기 위해서다.

{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "Kreact.createElement",
"pragmaFrag": "Kreact.fragment"
}
]
],
"presets": [
"@babel/preset-typescript",
[
"@babel/preset-env",
{
"targets": {
"browsers": [">= 1%"]
}
}
]
]
}

그리고 웹팩 설정을 했다. 기존 babel-loader에서 추가로 설정을 해줘야한다.

module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/i,
use: 'babel-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".js", ".ts", ".jsx", ".tsx", ".json"],
alias: {
'@': path.join(__dirname, 'src'),
},
},

이참에 alias 설정도 해줘서 import할 때 지저분하지 않게 했다.

타입스크립트로 마이그레이션

파일들을 tsx, ts로 바꾸고 타입 지정을 해주었다.

대표적으로 useState만 보자면

function useState<S>(
initialState: S | (() => S)
): [S, (newState: S | ((prevState: S) => S)) => void] {
let stateIndex = _stateIndex++;

if (_states[stateIndex] === undefined) {
if (initialState instanceof Function) initialState = initialState();
_states[stateIndex] = initialState;
}
let state = _states[stateIndex];

const setState = (newState: S) => {
if (typeof newState === 'function') newState = newState(state);
if (Object.is(_states[stateIndex], newState)) return;
_states[stateIndex] = newState;
_stateIndex = 0;
_render();
};

return [state, setState];
}

그리고 Kreact 네임스페이스를 만들어주었다.

// core/index.d.ts

declare namespace Kreact {
interface KreactElement {
type: any;
props: {
children: KreactElement[];
key?: any;
ref?: KreactRef;
nodeValue?: any;
};
}

interface KreactFragment {
type: 'FRAGMENT';
props: {
children: KreactElement[];
key?: any;
};
}

type KreactNode = ReactElement | string | number | KreactFragment | boolean | null | undefined;

//...
}

이렇게 함으로써 React.ReactNode처럼 사용할 수 있다.

import Header from './Header';
import styles from './index.module.css';

interface LayoutProps {
children?: Kreact.KreactNode;
}

export default function Layout({ children }: LayoutProps) {
return (
<div className={styles.layout}>
<Header />
<main className={styles.main}>{children}</main>
</div>
);
}

여기서 문제가 살짝 있긴 하다. 지금은 children?을 해서 선택적으로 받을 수 있게 했는데, 이걸 만약 children으로 했을 때 prop으로 children을 넘겨주면 ts 에러가 발생한다.

core에서 처리를 해두어서 실제로는 문제가 없지만, ts에서는 문제가 있다고 판단한다.

태그로 감싼걸 children으로 인식시킬 방법을 찾아봐야겠다.

import Kreact from 'kreact' 지우기

실제 리액트 써보면 요즘은 import React from 'react' 선언 안해도 된다. 옛날옛적 React 17 전에는 import React from 'react' 선언을 해줘야 했지만 지금은 안써도 된다.

내부적으로 JSX transformer가 자동으로 import해주기 때문이다.

나도 Auto-import 하고싶다!!! 웹팩 플러그인을 찾아보니 이런게 있었다.

// webpack.config.js
const webpack = require('webpack');

module.exports = {
plugins: [
new webpack.ProvidePlugin({
Kreact: '@/core/Kreact',
}),
],

//...
};

이렇게 하면 빌드될 때 자동으로 Kreact를 import 해서 import Kreact from 'kreact'를 안해줘도 된다!


내일 할 일

  • 알고리즘 문제 풀이
  • 크롬익스텐션 리팩토링 및 기능 개발
  • TIL 마이그레이션 프로젝트 시작..?
  • 오후 9시 CS 스터디 회의